#include "movingChargeTcpServer.h"
#include <QFileInfo>
#include <QSettings>
#define mJsonMaxLength  (1024*4)

inline bool check_json_string_member_safe(rapidjson::Document& dom,std::string mem)
{
    if (!dom.HasMember(mem.c_str()) || !dom[mem.c_str()].IsString())
    {
        return false;
    }
    return true;
}

MovingChargeTcpServer::MovingChargeTcpServer()
{

}

MovingChargeTcpServer::~MovingChargeTcpServer()
{
    LOG(INFO) << "~MovingChargeTcpServer() start, mWorkerRunnig " << mWorkerRunnig << std::endl;
    if(mWorkerRunnig){
        std::unique_lock<std::mutex> lk(mWorkerProcMutex);
        mJsonstr = "";
        mWorkerRecvStatus = true;
        mWorkerRunnig = false;

        mWorkercond.notify_all();
        worker.join();
    }

    LOG(INFO) << "~MovingChargeTcpServer() end!" << std::endl;
}

bool MovingChargeTcpServer::init()
{
    if(true == mInited){
        return true;
    }

    loadINI();
    print_base_info();
    m_server.init(localPort, localIP);
    m_server.registeCb(std::bind(&MovingChargeTcpServer::parseDitInfo, this, std::placeholders::_1, std::placeholders::_2));
    if(!m_server.start()){
        LOG(ERROR)<<"ChargeRobotServer init failed \n";
        return false;
    }
    mInited = true;

    if(false == mWorkerRunnig){
        LOG(INFO) << "start workThread thread\n";
        mWorkerRunnig = true;
        worker = std::thread(&MovingChargeTcpServer::workThreadFun, this);
    }
    return true;
}

void MovingChargeTcpServer::slotReplyClient(std::string num, std::string reslut)
{
    //reply client
    std::string reply;
    rapidjson::StringBuffer strBuf;
    rapidjson::Writer<rapidjson::StringBuffer> writer(strBuf);
    writer.StartObject();

    writer.Key("Num");
    writer.String(num.c_str());

    writer.Key("Reslut");
    writer.String(reslut.c_str());
    writer.EndObject();

    reply = strBuf.GetString();
    reply += "$&";
    m_server.activeSend((char*)reply.data(),reply.length());

}
void MovingChargeTcpServer::parseDitInfo(const char *data, int size)
{
    LOG(INFO)<<"data =" << data;
    LOG(INFO)<<"size =" << size;
    if(data[size-2] != '$' && data[size-1] != '&')
    {
        LOG(INFO)<<"parseDitInfo sparator err!";
        if(mJsonstr.length() + size <= mJsonMaxLength){
            LOG(INFO)<<"Append data to mJsonstr!";
            {
                std::unique_lock<std::mutex> res_lk(mResMutex);
                mJsonstr += std::string(data, size);
            }

        }else{
            LOG(INFO)<<"Clean mJsonstr!";
            {
                std::unique_lock<std::mutex> res_lk(mResMutex);
                mJsonstr = "";
            }

        }
        return;
    }

    if(mWorkerRecvStatus == false){
        {
            std::unique_lock<std::mutex> lk(mWorkerProcMutex);
            {
                std::unique_lock<std::mutex> res_lk(mResMutex);
                mJsonstr += std::string(data, size-2);
            }
            mWorkerRecvStatus = true;
        }
        mWorkercond.notify_all();
    }else{
        LOG(ERROR)<<"MovingChargeTcpServer work thread is busy!";
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

void MovingChargeTcpServer::workThreadFun()
{
    LOG(INFO) << "workThreadFun start!" << std::endl;
    std::string jsonStr ="";
    while(mWorkerRunnig){
        std::unique_lock<std::mutex> lk(mWorkerProcMutex);
        mWorkerRecvStatus = false;
        LOG(INFO) << "mWorkercond wait start!" << std::endl;
        mWorkercond.wait(lk, [this]{return mWorkerRecvStatus;});
        LOG(INFO) << "mWorkercond wait end!" << std::endl;
        if(!mWorkerRunnig) {
            LOG(INFO) << "workThreadFun out of while!" << std::endl;
            break;
        }

        {
            std::unique_lock<std::mutex> res_lk(mResMutex);
            jsonStr = mJsonstr;
            mJsonstr = "";
        }

        LOG(INFO) << "recv jsonStr = " << jsonStr << std::endl;
        rapidjson::Document dom;
        if (dom.Parse(jsonStr.c_str()).HasParseError())
        {
            LOG(ERROR) << "JSON HasParseError!";
            continue;
        }

        std::string reply;
        std::string action = dom["Action"].GetString();
        std::string numStr = dom["PointNum"].GetString();
        if(action == "Moving"){
            LOG(INFO) << "Moving PointNum "<< numStr << std::endl;
        }else {
            LOG(ERROR) << "Action not support!" << std::endl;
            continue;
        }

        emit sigMoveServo(1.0);


    }
    LOG(INFO) << "workThreadFun end!" << std::endl;
}

void MovingChargeTcpServer::loadINI()
{
    QFileInfo fileInfo(CONFIG_FILE_PATH);
    if(fileInfo.isFile())
    {
        LOG(INFO) << "Using config file !"<< std::endl;
        QSettings setting(CONFIG_FILE_PATH, QSettings::IniFormat);
        setting.setIniCodec("utf-8");
        localIP = setting.value("/MOVING_CHARGE_SERVER/serverIP").toString().toStdString();
        localPort  = setting.value("/MOVING_CHARGE_SERVER/serverPort").toInt();
    }else{
        LOG(INFO) << "Using default config !"<< std::endl;
    }
}

void MovingChargeTcpServer::print_base_info()
{
    LOG(INFO) << "localIP:" << localIP << std::endl;
    LOG(INFO) << "localPort:" << localPort << std::endl;
}
